/*
 *
 *  * Copyright (c) [2019-2021] [NorthLan](lan6995@gmail.com)
 *  *
 *  * Licensed under the Apache License, Version 2.0 (the "License");
 *  * you may not use this file except in compliance with the License.
 *  * You may obtain a copy of the License at
 *  *
 *  *     http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  * Unless required by applicable law or agreed to in writing, software
 *  * distributed under the License is distributed on an "AS IS" BASIS,
 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  * See the License for the specific language governing permissions and
 *  * limitations under the License.
 *
 */

package org.lan.iti.cloud.security.config.annotation.web;


import org.lan.iti.cloud.security.config.annotation.SecurityBuilder;
import org.lan.iti.cloud.security.config.annotation.SecurityConfigurer;
import org.lan.iti.cloud.security.config.annotation.web.builders.HttpSecurity;
import org.lan.iti.iha.security.web.DefaultSecurityFilterChain;
import org.springframework.web.filter.CorsFilter;

import javax.servlet.Filter;

/**
 * @author NorthLan
 * @date 2021/10/15
 * @url https://blog.noahlan.com
 */
public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
        extends SecurityBuilder<DefaultSecurityFilterChain> {

    /**
     * Gets the {@link SecurityConfigurer} by its class name or <code>null</code> if not
     * found. Note that object hierarchies are not considered.
     *
     * @param clazz the Class of the {@link SecurityConfigurer} to attempt to get.
     */
    <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(Class<C> clazz);

    /**
     * Removes the {@link SecurityConfigurer} by its class name or <code>null</code> if
     * not found. Note that object hierarchies are not considered.
     *
     * @param clazz the Class of the {@link SecurityConfigurer} to attempt to remove.
     * @return the {@link SecurityConfigurer} that was removed or null if not found
     */
    <C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(Class<C> clazz);

    /**
     * Sets an object that is shared by multiple {@link SecurityConfigurer}.
     *
     * @param sharedType the Class to key the shared object by.
     * @param object     the Object to store
     */
    <C> void setSharedObject(Class<C> sharedType, C object);

    /**
     * Gets a shared Object. Note that object heirarchies are not considered.
     *
     * @param sharedType the type of the shared Object
     * @return the shared Object or null if it is not found
     */
    <C> C getSharedObject(Class<C> sharedType);

//    /**
//     * Allows adding an additional {@link AuthenticationProvider} to be used
//     * @param authenticationProvider the {@link AuthenticationProvider} to be added
//     * @return the {@link HttpSecurity} for further customizations
//     */
//    H authenticationProvider(AuthenticationProvider authenticationProvider);
//
//    /**
//     * Allows adding an additional {@link UserDetailsService} to be used
//     * @param userDetailsService the {@link UserDetailsService} to be added
//     * @return the {@link HttpSecurity} for further customizations
//     */
//    H userDetailsService(UserDetailsService userDetailsService) throws Exception;

    /**
     * Allows adding a {@link Filter} after one of the known {@link Filter} classes. The
     * known {@link Filter} instances are either a {@link Filter} listed in
     * {@link #addFilter(Filter)} or a {@link Filter} that has already been added using
     * {@link #addFilterAfter(Filter, Class)} or {@link #addFilterBefore(Filter, Class)}.
     *
     * @param filter      the {@link Filter} to register after the type {@code afterFilter}
     * @param afterFilter the Class of the known {@link Filter}.
     * @return the {@link HttpSecurity} for further customizations
     */
    H addFilterAfter(Filter filter, Class<? extends Filter> afterFilter);

    /**
     * Allows adding a {@link Filter} before one of the known {@link Filter} classes. The
     * known {@link Filter} instances are either a {@link Filter} listed in
     * {@link #addFilter(Filter)} or a {@link Filter} that has already been added using
     * {@link #addFilterAfter(Filter, Class)} or {@link #addFilterBefore(Filter, Class)}.
     *
     * @param filter       the {@link Filter} to register before the type {@code beforeFilter}
     * @param beforeFilter the Class of the known {@link Filter}.
     * @return the {@link HttpSecurity} for further customizations
     */
    H addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter);

    /**
     * Adds a {@link Filter} that must be an instance of or extend one of the Filters
     * provided within the Security framework. The method ensures that the ordering of the
     * Filters is automatically taken care of.
     * <p>
     * The ordering of the Filters is:
     *
     * <ul>
     *      <li>{@link org.lan.iti.cloud.security.context.SecurityContextPersistenceFilter}</li>
     *      <li>{@link CorsFilter}</li>
     *      <li>{@link CsrfFilter}</li>
     *      <li>{@link ConcurrentSessionFilter}</li>
     *      <li>{@link oauth2.web.BearerTokenAuthenticationFilter}</li>
     *      <li>{@link RequestCacheAwareFilter}</li>
     *      <li>{@link SecurityContextHolderAwareRequestFilter}</li>
     *      <li>{@link org.lan.iti.cloud.security.context.AnonymousAuthenticationFilter}</li>
     *      <li>{@link SessionManagementFilter}</li>
     *      <li>{@link ExceptionTranslationFilter}</li>
     *      <li>{@link FilterSecurityInterceptor}</li>
     *      <li>{@link AuthorizationFilter}</li>
     *      <li>{@link SwitchUserFilter}</li>
     * </ul>
     *
     * @param filter the {@link Filter} to add
     * @return the {@link HttpSecurity} for further customizations
     * @see org.lan.iti.cloud.security.config.annotation.web.builders.FilterOrderRegistration
     */
    H addFilter(Filter filter);
}
